準備技術:
利用Vaadin提供的範例來實做一個JPA。
先了解Vaadin對於JPA的流程和一般JPA不同,一般只要JPA implement就可以讓Servlet掛載,而Vaadin要有個container負責這種掛載。 下圖解釋我們需要的工具,我選的JPA是J2SE提供的,implement則是選Eclipse Link,Database是H2。
整個專案的目錄與檔案如圖。
首先處理資料庫部分,我利用POJO處理與資料庫欄位的對應並設Setter與 Getter,做了Person.Java與Department.Java,以下程式為部分。
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@OneToMany(mappedBy = "department")
private Set<Person> persons;
@Transient
private Boolean superDepartment;
@ManyToOne
private Department parent;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Person> getPersons() {
return persons;
}
public void setPersons(Set<Person> persons) {
this.persons = persons;
}
public Department getParent() {
return parent;
}
public void setParent(Department parent) {
this.parent = parent;
}
public boolean isSuperDepartment() {
if (superDepartment == null) {
superDepartment = getPersons().size() == 0;
}
return superDepartment;
}
@Transient
public String getHierarchicalName() {
if (parent != null) {
return parent.toString() + " : " + name;
}
return name;
}
@Override
public String toString() {
return getHierarchicalName();
}
}
在src目錄,我設META-INF目錄,撰寫persistence.xml 設置eclipse link JPA implement。
<persistence-unit name="addressbook">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.jdbc.platform" value="org.eclipse.persistence.platform.database.H2Platform" />
<property name="eclipselink.jdbc.driver" value="org.h2.Driver" />
<property name="eclipselink.jdbc.url" value="jdbc:h2:tcp://localhost/~/test" />
<property name="eclipselink.jdbc.user" value="sa" />
<property name="eclipselink.jdbc.password" value="" />
<property name="eclipselink.logging.level" value="FINE" />
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
</properties>
</persistence-unit>
撰寫JPA container對應相關的Class。
@SuppressWarnings("serial")
public class HierarchicalDepartmentContainer extends JPAContainer {
public HierarchicalDepartmentContainer() {
super(Department.class);
setEntityProvider(new CachingLocalEntityProvider<Department>(
Department.class,
JPAContainerFactory
.createEntityManagerForPersistenceUnit(JpaaddressbookUI.PERSISTENCE_UNIT)));
setParentProperty("parent");
}
@Override
public boolean areChildrenAllowed(Object itemId) {
return super.areChildrenAllowed(itemId)
&& getItem(itemId).getEntity().isSuperDepartment();
}
}
撰寫UI的設定
@SuppressWarnings("serial")
public class AddressBookMainView extends HorizontalSplitPanel implements
ComponentContainer {
private Tree groupTree;
private Table personTable;
private TextField searchField;
private Button newButton;
private Button deleteButton;
private Button editButton;
private JPAContainer<Department> departments;
private JPAContainer<Person> persons;
private Department departmentFilter;
private String textFilter;
public AddressBookMainView() {
departments = new HierarchicalDepartmentContainer();
persons = JPAContainerFactory.make(Person.class,
JpaaddressbookUI.PERSISTENCE_UNIT);
buildTree();
buildMainArea();
setSplitPosition(30);
}
@SuppressWarnings("deprecation")
private void buildMainArea() {
VerticalLayout verticalLayout = new VerticalLayout();
setSecondComponent(verticalLayout);
personTable = new Table(null, persons);
personTable.setSelectable(true);
personTable.setImmediate(true);
personTable.addListener(new Property.ValueChangeListener() {
@Override
public void valueChange(ValueChangeEvent event) {
setModificationsEnabled(event.getProperty().getValue() != null);
}
private void setModificationsEnabled(boolean b) {
deleteButton.setEnabled(b);
editButton.setEnabled(b);
}
});
personTable.setSizeFull();
// personTable.setSelectable(true);
personTable.addListener(new ItemClickListener() {
@Override
public void itemClick(ItemClickEvent event) {
if (event.isDoubleClick()) {
personTable.select(event.getItemId());
}
}
});
personTable.setVisibleColumns(new Object[] { "firstName", "lastName",
"department", "phoneNumber", "street", "city", "zipCode" });
HorizontalLayout toolbar = new HorizontalLayout();
newButton = new Button("Add");
newButton.addClickListener(new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
final BeanItem<Person> newPersonItem = new BeanItem<Person>(
new Person());
PersonEditor personEditor = new PersonEditor(newPersonItem);
personEditor.addListener(new EditorSavedListener() {
@Override
public void editorSaved(EditorSavedEvent event) {
persons.addEntity(newPersonItem.getBean());
}
});
UI.getCurrent().addWindow(personEditor);
}
});
deleteButton = new Button("Delete");
deleteButton.addClickListener(new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
persons.removeItem(personTable.getValue());
}
});
deleteButton.setEnabled(false);
editButton = new Button("Edit");
editButton.addClickListener(new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
UI.getCurrent().addWindow(
new PersonEditor(personTable.getItem(personTable
.getValue())));
}
});
editButton.setEnabled(false);
searchField = new TextField();
searchField.setInputPrompt("Search by name");
searchField.addTextChangeListener(new TextChangeListener() {
@Override
public void textChange(TextChangeEvent event) {
textFilter = event.getText();
updateFilters();
}
});
toolbar.addComponent(newButton);
toolbar.addComponent(deleteButton);
toolbar.addComponent(editButton);
toolbar.addComponent(searchField);
toolbar.setWidth("100%");
toolbar.setExpandRatio(searchField, 1);
toolbar.setComponentAlignment(searchField, Alignment.TOP_RIGHT);
verticalLayout.addComponent(toolbar);
verticalLayout.addComponent(personTable);
verticalLayout.setExpandRatio(personTable, 1);
verticalLayout.setSizeFull();
}
@SuppressWarnings("deprecation")
private void buildTree() {
groupTree = new Tree(null, departments);
groupTree.setItemCaptionPropertyId("name");
groupTree.setImmediate(true);
groupTree.setSelectable(true);
groupTree.addListener(new Property.ValueChangeListener() {
@Override
public void valueChange(ValueChangeEvent event) {
Object id = event.getProperty().getValue();
if (id != null) {
Department entity = departments.getItem(id).getEntity();
departmentFilter = entity;
} else if (departmentFilter != null) {
departmentFilter = null;
}
updateFilters();
}
});
setFirstComponent(groupTree);
}
private void updateFilters() {
persons.setApplyFiltersImmediately(false);
persons.removeAllContainerFilters();
if (departmentFilter != null) {
// two level hierarchy at max in our demo
if (departmentFilter.getParent() == null) {
persons.addContainerFilter(new Equal("department.parent",
departmentFilter));
} else {
persons.addContainerFilter(new Equal("department",
departmentFilter));
}
}
if (textFilter != null && !textFilter.equals("")) {
Or or = new Or(new Like("firstName", textFilter + "%", false),
new Like("lastName", textFilter + "%", false));
persons.addContainerFilter(or);
}
persons.applyFilters();
}
}
然後就可以deploy了。
參考資料
Day13 結束